package app

import (
	"cade/src/core/evtmgr"
	"cade/src/core/log"
	"cade/src/core/net/tcp"
	"cade/src/core/net/websocket"
	"cade/src/core/packet"
	"strings"
	"sync"
)

// ============================================================================

var botobj *Bot
var wg sync.WaitGroup

var botname string

// ============================================================================

func Start(addr string, username string) {
	botname = username

	// do connect
	wg.Add(2)
	go func() {
		defer wg.Done()

		if strings.HasPrefix(addr, "ws://") || strings.HasPrefix(addr, "wss://") {
			// websocket
			websocket.Connect(addr, 5000, func(err error, sock *websocket.Socket) {
				defer wg.Done()
				on_connect(err, sock)
			})
		} else {
			// tcp
			tcp.Connect(addr, 5000, func(err error, sock *tcp.Socket) {
				defer wg.Done()
				on_connect(err, sock)
			})
		}
	}()
}

func Stop() {
	// wait for all connect i/o
	wg.Wait()

	// close all bots
	if botobj != nil {
		botobj.Close()
	}
}

func on_connect(err error, sock socket_t) {
	if err != nil {
		log.Error("connect to server failed:", err)
		return
	}

	// add session
	botobj = new_bot(sock, 1, botname)

	botobj.Push(func() {
		botobj.OnConnected()
	})

	// sock event: data
	sock.OnData(func(buf []byte) {
		var p packet.Packet
		var err error

		for len(buf) > 0 {
			// read packet
			p, buf, err = botobj.preader.Read(buf)
			if err != nil {
				log.Warning("reading packet failed:", err)
				sock.Close()
				return
			}

			// no packet yet
			if p == nil {
				return
			}

			// got packet. dispatch
			botobj.Dispatch(p)
		}
	})

	// sock event: close
	sock.OnClose(func() {
		// remove bot
		botobj.Push(func() {
			botobj.OnDisconnected()

			// stop after disconnected event is consumed
			botobj.stop()

			// end-program check after disconnected event is consumed
			evtmgr.Fire("all.bot.dies")
		})
	})

	// run
	botobj.run()
}
